using Microsoft.AspNetCore.Mvc;
using UniversalAdmin.Application.Dtos.File;
using UniversalAdmin.Application.Services.Interfaces;
using UniversalAdmin.Application.Common;

namespace UniversalAdmin.Api.Controllers;

[ApiController]
[Route("api/[controller]")]
public class FileController : ControllerBase
{
    private readonly IFileService _fileService;
    private readonly IWebHostEnvironment _webHostEnvironment;
    private readonly IConfiguration _configuration;
    private readonly ILogger<FileController> _logger;

    public FileController(
        IFileService fileService,
        IWebHostEnvironment webHostEnvironment,
        IConfiguration configuration,
        ILogger<FileController> logger)
    {
        _fileService = fileService;
        _webHostEnvironment = webHostEnvironment;
        _configuration = configuration;
        _logger = logger;
    }

    /// <summary>
    /// 上传文件
    /// </summary>
    /// <param name="file">上传的文件</param>
    /// <returns>上传结果</returns>
    [HttpPost("upload")]
    public async Task<IActionResult> UploadFile(IFormFile file)
    {
        if (file == null || file.Length == 0)
            return BadRequest(ApiResult.Fail(400, "文件不能为空"));

        try
        {
            // 验证文件大小 (默认最大 10MB)
            var maxFileSize = _configuration.GetValue<long>("FileUpload:MaxFileSize", 10 * 1024 * 1024);
            if (file.Length > maxFileSize)
                return BadRequest(ApiResult.Fail(400, $"文件大小不能超过 {maxFileSize / 1024 / 1024}MB"));

            // 验证文件类型
            var allowedExtensions = _configuration.GetSection("FileUpload:AllowedExtensions").Get<string[]>()
                ?? new[] { ".jpg", ".jpeg", ".png", ".gif", ".pdf", ".doc", ".docx", ".txt" };

            var fileExtension = Path.GetExtension(file.FileName).ToLowerInvariant();
            if (!allowedExtensions.Contains(fileExtension))
                return BadRequest(ApiResult.Fail(400, $"不支持的文件类型: {fileExtension}"));

            // 生成唯一文件名
            var fileName = $"{DateTime.UtcNow:yyyyMMdd}_{Guid.NewGuid()}{fileExtension}";

            // 创建保存路径
            var dateFolder = DateTime.UtcNow.ToString("yyyy/MM/dd");
            var uploadPath = Path.Combine(_webHostEnvironment.WebRootPath ?? "wwwroot", "uploads", dateFolder);

            if (!Directory.Exists(uploadPath))
                Directory.CreateDirectory(uploadPath);

            var filePath = Path.Combine(uploadPath, fileName);
            var relativePath = $"/uploads/{dateFolder}/{fileName}".Replace("\\", "/");

            // 保存文件
            using (var stream = new FileStream(filePath, FileMode.Create))
            {
                await file.CopyToAsync(stream);
            }

            // 获取当前用户ID (这里需要从认证信息中获取，暂时设为null)
            Guid? currentUserId = null; // TODO: 从JWT或其他认证方式获取当前用户ID

            // 构建完整的文件URL - 存储到数据库中
            var baseUrl = _configuration.GetValue<string>("FileUpload:BaseUrl") ?? $"{Request.Scheme}://{Request.Host}";
            var fullUrl = $"{baseUrl.TrimEnd('/')}{relativePath}";

            // 保存文件信息到数据库 - path字段存储完整URL
            var fileDto = await _fileService.SaveFileInfoAsync(
                fileName,
                file.FileName,
                file.ContentType,
                file.Length,
                fullUrl,  // 存储完整URL而不是相对路径
                currentUserId);

            // 直接使用数据库中的URL
            fileDto.Url = fileDto.Path;

            _logger.LogInformation("文件上传成功: {FileName}, 大小: {FileSize} bytes", fileName, file.Length);

            return Ok(ApiResult.Success(new FileUploadDto
            {
                Id = fileDto.Id,
                Name = fileDto.Name,
                OriginalName = fileDto.OriginalName,
                Path = fileDto.Path, // 现在存储的是完整URL
                Url = fileDto.Url,   // 与Path相同
                Size = fileDto.Size,
                MimeType = fileDto.MimeType,
                CreatedAt = fileDto.CreatedAt
            }, "上传成功"));
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "文件上传失败: {FileName}", file.FileName);
            return BadRequest(ApiResult.Fail(500, $"文件上传失败: {ex.Message}"));
        }
    }

    /// <summary>
    /// 获取文件列表
    /// </summary>
    /// <param name="query">查询参数</param>
    /// <returns>文件列表</returns>
    [HttpGet]
    public async Task<IActionResult> GetFiles([FromQuery] FileQueryDto query)
    {
        try
        {
            var (items, totalCount) = await _fileService.GetFilesAsync(
                query.PageIndex,
                query.PageSize,
                query.Keyword,
                query.MimeType,
                query.UserId);

            // Path字段已经存储完整URL，直接设置Url
            foreach (var item in items)
            {
                item.Url = item.Path;
            }

            var result = new
            {
                Items = items,
                PageIndex = query.PageIndex,
                PageSize = query.PageSize,
                TotalCount = totalCount,
                TotalPages = (int)Math.Ceiling((double)totalCount / query.PageSize)
            };

            return Ok(ApiResult.Success(result, "获取成功"));
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "获取文件列表失败");
            return BadRequest(ApiResult.Fail(500, "获取文件列表失败"));
        }
    }

    /// <summary>
    /// 根据ID获取文件信息
    /// </summary>
    /// <param name="id">文件ID</param>
    /// <returns>文件信息</returns>
    [HttpGet("{id}")]
    public async Task<IActionResult> GetFileById(Guid id)
    {
        try
        {
            var file = await _fileService.GetByIdAsync(id);
            if (file == null)
                return NotFound(ApiResult.Fail(404, "文件不存在"));

            // Path字段已经存储完整URL，直接设置
            file.Url = file.Path;

            return Ok(ApiResult.Success(file, "获取成功"));
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "获取文件信息失败: {FileId}", id);
            return BadRequest(ApiResult.Fail(500, "获取文件信息失败"));
        }
    }

    /// <summary>
    /// 获取文件预览信息（用于VS Code中预览）
    /// </summary>
    /// <param name="id">文件ID</param>
    /// <returns>文件预览信息</returns>
    [HttpGet("{id}/preview")]
    public async Task<IActionResult> PreviewFile(Guid id)
    {
        try
        {
            var fileEntity = await _fileService.GetFileEntityAsync(id);
            if (fileEntity == null)
                return NotFound(ApiResult.Fail(404, "文件不存在"));

            var physicalPath = GetPhysicalPath(fileEntity.Path);
            if (!System.IO.File.Exists(physicalPath))
            {
                _logger.LogWarning("物理文件不存在: {FilePath}", physicalPath);
                return NotFound(ApiResult.Fail(404, "物理文件不存在"));
            }

            string? previewContent = null;
            bool canPreview = false;

            // 如果是文本文件，读取内容用于预览
            if (fileEntity.MimeType?.StartsWith("text/") == true ||
                Path.GetExtension(fileEntity.OriginalName).ToLowerInvariant() == ".txt")
            {
                try
                {
                    var fileInfo = new FileInfo(physicalPath);
                    if (fileInfo.Length <= 5120) // 限制5KB以内的文件可以预览
                    {
                        previewContent = await System.IO.File.ReadAllTextAsync(physicalPath, System.Text.Encoding.UTF8);
                        canPreview = true;
                    }
                    else
                    {
                        // 只读取前2KB用于预览
                        var bytes = new byte[2048];
                        using var stream = System.IO.File.OpenRead(physicalPath);
                        var bytesRead = await stream.ReadAsync(bytes, 0, 2048);
                        previewContent = System.Text.Encoding.UTF8.GetString(bytes, 0, bytesRead) + "\n\n... (文件过大，仅显示前2KB内容)";
                        canPreview = true;
                    }
                }
                catch (Exception ex)
                {
                    previewContent = $"无法读取文件内容：{ex.Message}";
                    canPreview = false;
                }
            }

            var baseUrl = _configuration.GetValue<string>("FileUpload:BaseUrl") ?? $"{Request.Scheme}://{Request.Host}";

            var result = new
            {
                FileInfo = new
                {
                    Id = fileEntity.Id,
                    FileName = fileEntity.OriginalName,
                    FileSize = fileEntity.Size,
                    FileSizeFormatted = FormatFileSize(fileEntity.Size),
                    MimeType = fileEntity.MimeType,
                    Extension = Path.GetExtension(fileEntity.OriginalName),
                    CreatedAt = fileEntity.CreatedAt,
                    StaticUrl = fileEntity.Path
                },
                Preview = new
                {
                    CanPreview = canPreview,
                    Content = previewContent,
                    IsTextFile = fileEntity.MimeType?.StartsWith("text/") == true,
                    PreviewType = canPreview ? "text" : "not_supported"
                },
                Actions = new
                {
                    DownloadLinksUrl = $"{baseUrl}/api/file/{id}/download-links",
                    DirectDownloadUrl = $"{baseUrl}/api/file/{id}/download-file"
                }
            };

            return Ok(ApiResult.Success(result, "获取文件预览成功"));
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "获取文件预览失败: {FileId}", id);
            return BadRequest(ApiResult.Fail(500, "获取文件预览失败"));
        }
    }

    /// <summary>
    /// 获取文件下载链接（显示下载链接，点击可在浏览器中下载）
    /// </summary>
    /// <param name="id">文件ID</param>
    /// <returns>下载链接信息</returns>
    [HttpGet("{id}/download-links")]
    public async Task<IActionResult> GetDownloadLinks(Guid id)
    {
        try
        {
            var fileEntity = await _fileService.GetFileEntityAsync(id);
            if (fileEntity == null)
                return NotFound(ApiResult.Fail(404, "文件不存在"));

            var physicalPath = GetPhysicalPath(fileEntity.Path);
            if (!System.IO.File.Exists(physicalPath))
            {
                _logger.LogWarning("物理文件不存在: {FilePath}", physicalPath);
                return NotFound(ApiResult.Fail(404, "物理文件不存在"));
            }

            var baseUrl = _configuration.GetValue<string>("FileUpload:BaseUrl") ?? $"{Request.Scheme}://{Request.Host}";

            var result = new
            {
                FileInfo = new
                {
                    Id = fileEntity.Id,
                    FileName = fileEntity.OriginalName,
                    FileSize = fileEntity.Size,
                    FileSizeFormatted = FormatFileSize(fileEntity.Size),
                    MimeType = fileEntity.MimeType,
                    CreatedAt = fileEntity.CreatedAt
                },
                DownloadLinks = new
                {
                    // API下载链接（强制下载）
                    ApiDownload = new
                    {
                        Url = $"{baseUrl}/api/file/{id}/download-file",
                        Description = "通过API下载文件（强制下载）",
                        Method = "GET"
                    },
                    // 静态文件链接（浏览器中打开或下载）
                    StaticAccess = new
                    {
                        Url = fileEntity.Path,
                        Description = "静态文件访问（浏览器中预览或下载）",
                        Method = "GET"
                    },
                    // 预览链接
                    Preview = new
                    {
                        Url = $"{baseUrl}/api/file/{id}/preview",
                        Description = "文件预览信息",
                        Method = "GET"
                    }
                },
                Instructions = new[]
                {
                    "1. 点击 'ApiDownload.Url' 可直接下载文件到本地",
                    "2. 点击 'StaticAccess.Url' 可在浏览器中预览或下载文件",
                    "3. 点击 'Preview.Url' 可查看文件详细信息和预览内容"
                }
            };

            // 添加自定义响应头，方便客户端获取下载信息
            Response.Headers["X-File-Name"] = fileEntity.OriginalName;
            Response.Headers["X-File-Size"] = fileEntity.Size.ToString();
            Response.Headers["X-Download-Url"] = $"{baseUrl}/api/file/{id}/download-file";
            Response.Headers["X-Static-Url"] = fileEntity.Path;

            return Ok(ApiResult.Success(result, "获取下载链接成功"));
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "获取下载链接失败: {FileId}", id);
            return BadRequest(ApiResult.Fail(500, "获取下载链接失败"));
        }
    }

    /// <summary>
    /// 直接下载文件（返回文件流，强制下载）
    /// </summary>
    /// <param name="id">文件ID</param>
    /// <returns>文件内容</returns>
    [HttpGet("{id}/download-file")]
    public async Task<IActionResult> DownloadFileStream(Guid id)
    {
        try
        {
            var fileEntity = await _fileService.GetFileEntityAsync(id);
            if (fileEntity == null)
                return NotFound(ApiResult.Fail(404, "文件不存在"));

            var physicalPath = GetPhysicalPath(fileEntity.Path);
            if (!System.IO.File.Exists(physicalPath))
            {
                _logger.LogWarning("物理文件不存在: {FilePath}", physicalPath);
                return NotFound(ApiResult.Fail(404, "物理文件不存在"));
            }

            var fileBytes = await System.IO.File.ReadAllBytesAsync(physicalPath);
            var contentType = fileEntity.MimeType ?? "application/octet-stream";

            // 如果是文本类型，强制加charset=utf-8，避免浏览器乱码
            if (contentType.StartsWith("text/plain"))
            {
                if (!contentType.Contains("charset"))
                {
                    contentType = "text/plain; charset=utf-8";
                }
            }

            // 设置响应头强制下载 - 对文件名进行URL编码以支持中文
            var encodedFileName = System.Web.HttpUtility.UrlEncode(fileEntity.OriginalName, System.Text.Encoding.UTF8);
            Response.Headers["Content-Disposition"] = $"attachment; filename*=UTF-8''{encodedFileName}";

            _logger.LogInformation("文件下载: {FileName}, 用户: Anonymous", fileEntity.OriginalName);

            return File(fileBytes, contentType, fileEntity.OriginalName);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "下载文件失败: {FileId}", id);
            return BadRequest(ApiResult.Fail(500, "下载文件失败"));
        }
    }

    /// <summary>
    /// 删除文件
    /// </summary>
    /// <param name="id">文件ID</param>
    /// <returns>删除结果</returns>
    [HttpDelete("{id}")]
    public async Task<IActionResult> DeleteFile(Guid id)
    {
        try
        {
            var fileEntity = await _fileService.GetFileEntityAsync(id);
            if (fileEntity == null)
                return NotFound(ApiResult.Fail(404, "文件不存在"));

            // 删除数据库记录
            var result = await _fileService.DeleteFileAsync(id);
            if (!result)
                return BadRequest(ApiResult.Fail(400, "删除文件失败"));

            // 删除物理文件
            try
            {
                var physicalPath = GetPhysicalPath(fileEntity.Path);
                if (System.IO.File.Exists(physicalPath))
                {
                    System.IO.File.Delete(physicalPath);
                    _logger.LogInformation("物理文件删除成功: {FilePath}", physicalPath);
                }
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "删除物理文件失败: {FilePath}", fileEntity.Path);
                // 即使物理文件删除失败，也认为删除成功，因为数据库记录已经删除
            }

            _logger.LogInformation("文件删除成功: {FileName}", fileEntity.Name);
            return Ok(ApiResult.Success(null, "删除成功"));
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "删除文件失败: {FileId}", id);
            return BadRequest(ApiResult.Fail(500, "删除文件失败"));
        }
    }

    private string GetPhysicalPath(string urlPath)
    {
        var webRootPath = _webHostEnvironment.WebRootPath ?? "wwwroot";

        // 从完整URL中提取相对路径
        string relativePath;
        if (urlPath.StartsWith("http"))
        {
            // 如果是完整URL，提取路径部分
            var uri = new Uri(urlPath);
            relativePath = uri.AbsolutePath;
        }
        else
        {
            // 如果已经是相对路径，直接使用
            relativePath = urlPath;
        }

        return Path.Combine(webRootPath, relativePath.TrimStart('/').Replace("/", Path.DirectorySeparatorChar.ToString()));
    }

    /// <summary>
    /// 格式化文件大小
    /// </summary>
    /// <param name="bytes">文件大小（字节）</param>
    /// <returns>格式化后的文件大小</returns>
    private string FormatFileSize(long bytes)
    {
        string[] suffixes = { "B", "KB", "MB", "GB", "TB" };
        int counter = 0;
        decimal number = bytes;
        while (Math.Round(number / 1024) >= 1)
        {
            number /= 1024;
            counter++;
        }
        return $"{number:n1} {suffixes[counter]}";
    }
}